#include <matsu.h>
#include <matsuExt.h>
#include <mio.h>

#include "SRRenderer2.h"
#include "SRShader.h"
#include "SRData.h"
#include "SRScene.h"
#include "SRPlatform.h"

#if _GLES2_

using namespace matsu;
using namespace mio;
using std::string;
using std::auto_ptr;

namespace sora
{
	// Uniform index.
	enum {
		UNIFORM_TRANSLATE,
		NUM_UNIFORMS
	};

	// Attribute index.
	enum {
		ATTRIB_VERTEX,
		ATTRIB_COLOR,
		NUM_ATTRIBUTES
	};

	GLint uniforms[NUM_UNIFORMS];	//TODO: 옮기기

	GLESRenderer2::GLESRenderer2()
	: Renderer(), screenwidth_(0), screenheight_(0)
	{
		vertexBuffer_ = NULL;
		indexBuffer_ = NULL;

		loadShaders();

		/*
		 //soil test
		 string path = mio::path::appPath("img_test.png");
		 GLuint tex_2d = SOIL_load_OGL_texture
		 (
		 path.c_str(),
		 SOIL_LOAD_AUTO,
		 SOIL_CREATE_NEW_ID,
		 SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT
		 );
		 int a = tex_2d;
		 */
	}
	GLESRenderer2::~GLESRenderer2()
	{
		if(indexBuffer_ != NULL)	delete(indexBuffer_);
		if(vertexBuffer_ != NULL)	delete(vertexBuffer_);
	}

	void GLESRenderer2::init()
	{
	}

	void GLESRenderer2::resize(int w, int h)
	{
		SR_ASSERT(w > 0);
		SR_ASSERT(h > 0);
		if(screenwidth_ != w || screenheight_ != h)
		{
			Console::console().print("Resize screen:%d, %d", w, h);
			screenwidth_ = w;
			screenheight_ = h;
		}
	}

	void GLESRenderer2::render()
	{
		SR_ASSERT(screenwidth_ > 0 && screenheight_ > 0);
		const int &screenwidth = screenwidth_;
		const int &screenheight = screenheight_;

		glViewport(0, 0, screenwidth, screenheight);

		//buffer 초기화는 다른 클래스로 분리가능할듯?
		glClearColor(0.5f, 0.5f, 0.5f, 1);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		/*
		for(int i = 0 ; i < 2 ; i++)
		{
			//set modelview + projection test
			mat4 modelview;
			if(i == 0)
			{
				//init projection matrix
				sora::Camera cam;
				cam.setOrtho(-160, 160, -240, 240, 0, 5);
				program_->applyCamera(cam);
				modelview = matsu::mat::translate<float>(0, 0, 0);
			}
			else
			{
				//init projection matrix
				sora::Camera cam;
				cam.setOrtho(0, 160, 0, 240, 0, 5);
				//cam.setOrtho(-160, 160, -240, 240, 0, 5);
				program_->applyCamera(cam);

				modelview = mat::zRotate<float>(90);
				//modelview = mat::translate<float>(0, 0, 0);
			}
			program_->applyModelview(modelview);

			{
				//무식하게 배열 떄려박는 방법으로 삼각형 적절히 그리기
				const sora::Vertex2 arrayVertices[] = {
					{{-50.0f, -86.6f}, {1, 0, 0, 1}},
					{{50.0f, -86.6f}, {1, 0, 0, 1}},
					{{0, 100.0f}, {1, 0, 0, 1}},
				};
				GLsizei vertexCount = sizeof(arrayVertices) / sizeof(sora::Vertex2);
				program_->applyVertex2AttribArray(arrayVertices, vertexCount, GL_TRIANGLES);
			}
			{
				//vertex index 사용
				const sora::Vertex2 indexVertices[] = {
					{{0, 0}, {0, 1, 0, 1}},
					{{0, 50}, {0, 1, 0, 1}},
					{{50, 0}, {0, 1, 0, 1}},
					{{50, 50}, {0, 1, 0, 1}}
				};
				const GLubyte indices[] = {0, 3, 1, 0, 2, 3};
				GLsizei indexCount = sizeof(indices) / sizeof(GLubyte);
				program_->applyVertex2Index(indexVertices, indices, indexCount, GL_TRIANGLES, GL_UNSIGNED_BYTE);
			}
			{
				if(indexBuffer_ == NULL)
				{
					//create vertex buffer object
					const sora::Vertex2 vertices[] = {
						{{50, 50}, {0, 0, 1, 1}},
						{{50, 100}, {0, 0, 1, 1}},
						{{100, 50}, {0, 0, 1, 1}},
						{{100, 100}, {0, 0, 1, 1}}
					};
					const GLubyte indices[] = {0, 3, 1, 0, 2, 3};
					int vertexCount = sizeof(vertices) / sizeof(sora::Vertex2);
					int indexCount = sizeof(indices) / sizeof(GLubyte);
					GLsizei stride = sizeof(sora::Vertex2);

					//create vbo for vertices
					vertexBuffer_ = new sora::VertexBufferObject(vertices, vertexCount, stride, GL_STATIC_DRAW);
					indexBuffer_ = new sora::IndexBufferObject(indices, indexCount, GL_UNSIGNED_BYTE, GL_TRIANGLES, GL_STATIC_DRAW);
				}

				//vertex buffer object 사용
				program_->applyVBO2(*vertexBuffer_, *indexBuffer_);
			}

		}
		*/
	}

	void GLESRenderer2::done()
	{

	}

	bool GLESRenderer2::loadShaders()
	{
		mio::FileReader reader;
		string vertShaderSrcPath = mio::path::appPath("simple.vsh");
		string fragShaderSrcPath = mio::path::appPath("simple.fsh");

		//load shader source
		string vertShaderSrc = reader.read(vertShaderSrcPath);
		Shader *vertShader = Shader::createVertShader(vertShaderSrc);

		string fragShaderSrc = reader.read(fragShaderSrcPath);
		Shader *fragShader = Shader::createFragShader(fragShaderSrc);

		program_ = auto_ptr<ShaderProgram>(new ShaderProgram(vertShader, fragShader));

		// Use shader program.
		program_->use();

		// Validate program before drawing. This is a good check, but only really necessary in a debug build.
		// DEBUG macro must be defined in your debug configurations if that's not already the case.
#if defined(DEBUG)
		if (!program_->validate())
		{
			mio::Console::console().print("Failed to validate program: %x", program_.get());
			return false;
		}
#endif
		return true;
	}
}

#endif